package wt

import (
	"crypto/tls"
	"net/http"
	"sync"

	"gitee.com/AlexWoo/arpc/alog"
	"gitee.com/AlexWoo/arpc/anet"
	"github.com/quic-go/quic-go"
	"github.com/quic-go/quic-go/http3"
	"github.com/quic-go/webtransport-go"
)

type CreateHandler func(*Connection) anet.Handler

type Server struct {
	server *webtransport.Server

	conf *ServerConf

	lctx *alog.LogCtx // Log Context

	path   string
	create CreateHandler

	wg *sync.WaitGroup
}

func loadTLSConfig(certFile, keyFile string) (*tls.Config, error) {
	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return nil, err
	}
	return &tls.Config{
		Certificates:       []tls.Certificate{cert},
		NextProtos:         []string{"h3"},
		InsecureSkipVerify: true,
	}, nil
}

func NewServer(c *ServerConf) *Server {
	s := &Server{
		conf: c,
	}

	s.lctx = &alog.LogCtx{}
	s.lctx.LogLevel = alog.Level[c.Log.LogLevel]
	s.lctx.Prefix = s.Prefix
	s.lctx.Suffix = s.Suffix

	tlsconf, err := loadTLSConfig(c.CertFile, c.CertKey)
	if err != nil {
		alog.LogError(nil, "Error loading TLS config: %v", err)
		return nil
	}

	s.server = &webtransport.Server{
		H3: http3.Server{
			Addr:            c.Addr,
			TLSConfig:       tlsconf,
			EnableDatagrams: true,
			QUICConfig: &quic.Config{
				EnableDatagrams: true,
			},
		},
		CheckOrigin: func(r *http.Request) bool { return true },
	}

	return s
}

func (s *Server) RegisteHandler(path string, ch CreateHandler) {
	s.path = path
	s.create = ch
}

func (s *Server) Run(wg *sync.WaitGroup) {
	s.wg = wg

	http.HandleFunc(s.path, s.handle)

	wg.Add(1)
	go func(wg *sync.WaitGroup) {
		defer wg.Done()

		alog.LogInfo(s.lctx, "WebTransport Server start listen %s", s.conf.Addr)

		if err := s.server.ListenAndServeTLS(s.conf.CertFile, s.conf.CertKey); err != nil {
			alog.LogError(s.lctx, "ListenAndServeTLS err %s", err)
			return
		}
	}(wg)
}

func (s *Server) Prefix() string {
	return "[WebTransport Server]"
}

func (s *Server) Suffix() string {
	return "addr:" + s.conf.Addr
}

func (s *Server) handle(w http.ResponseWriter, r *http.Request) {
	s.wg.Add(1)
	defer s.wg.Done()

	conn, err := s.server.Upgrade(w, r)
	if err != nil {
		alog.LogError(s.lctx, "Handler webtransport upgrade %v", err)
		return
	}

	c := newConnection(&s.conf.Log)
	c.conn = conn
	c.h = s.create(c)
	c.remote = conn.RemoteAddr().String()
	c.local = conn.LocalAddr().String()

	alog.LogInfo(c.lctx, "WebTransport Server accept new connection")

	c.loop()
}
